package com.expert.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.expert.context.BaseContext;
import com.expert.enums.ProjectStatus;
import com.expert.exception.AddException;
import com.expert.pojo.*;
import com.expert.service.*;
import com.expert.vo.ExpertExtractVo;
import com.expert.vo.ExtractAvoidOtherVo;
import com.expert.vo.ExtractInfoVo;
import com.expert.vo.ExtractOtherCondition;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName: ExtractServiceImpl
 * @Author: cxs
 * @Date: 2024/03/25 16:22
 * @Description:
 **/
@Service
public class ExtractServiceImpl implements ExtractService {


    @Autowired
    ExtractConditionService conditionService;
    @Autowired
    ExtractAvoidService extractAvoidService;
    @Autowired
    ExpertService expertService;
    @Autowired
    RabbitSendService service;
    @Autowired
    ProjectService projectService;

    @Autowired
    ExtractResultService extractResultService;
    /**
     * 获取项目的抽取条件和回避条件的信息
     *
     * @param id 项目id
     * @return
     */
    @Override
    public ExtractInfoVo getConditionAndAvoid(Long id) {

        ExtractInfoVo extractInfoVo=new ExtractInfoVo();
        //指定专家信息
        List<ExpertExtractVo> expertExtractVos=new ArrayList<>();
        //其他条件
        List<ExtractOtherCondition> otherConditions=new ArrayList<>();
        //1.查询项目相关的抽取条件
        List<ExtractCondition> conditionList = this.conditionService.lambdaQuery().eq(ExtractCondition::getProjectId, id).list();
        if (!conditionList.isEmpty()){
            conditionList.forEach(condition->{
                if (condition.getExtractDefaultExpert()!=null){
                    ExpertExtractVo expertExtractVo=new ExpertExtractVo();
                    expertExtractVo.setExpertId(condition.getExtractDefaultExpert());
                    expertExtractVo.setExpertIdNumber(condition.getExtractDefaultExpertIdNumber());
                    expertExtractVo.setExpertName(condition.getExtractDefaultExpertName());
                    String expertPhone = this.expertService.getById(condition.getExtractDefaultExpert()).getExpertPhone();
                    expertExtractVo.setExpertPhone(expertPhone);
                    expertExtractVos.add(expertExtractVo);
                }
                if(condition.getExtractCategory()!=null||StringUtils.isNotEmpty(condition.getExpertTitle())){
                    ExtractOtherCondition otherCondition=ExtractOtherCondition.builder()
                            .categoryId(condition.getExtractCategory())
                            .categoryName(condition.getExtractCategoryName())
                            .expertTitle(condition.getExpertTitle())
                            .extractNumber(condition.getExtractNumber())
                            .build();
                    otherConditions.add(otherCondition);
                }
            });
        }
        //2.查询项目相关的回避条件
        List<ExtractAvoid> extractAvoidList = this.extractAvoidService.lambdaQuery().eq(ExtractAvoid::getProjectId, id).list();
        List<ExpertExtractVo> expertAvoidVos=new ArrayList<>();
        StringJoiner avoidUnit=new StringJoiner("、");
        StringJoiner avoidRegion=new StringJoiner("、");
        if (!extractAvoidList.isEmpty()){
            extractAvoidList.forEach(avoid->{
                if (avoid.getAvoidDefaultExpert()!=null){
                    ExpertExtractVo expertExtractVo=new ExpertExtractVo();
                    expertExtractVo.setExpertId(avoid.getAvoidDefaultExpert());
                    expertExtractVo.setExpertIdNumber(avoid.getAvoidDefaultExpertIdNumber());
                    expertExtractVo.setExpertName(avoid.getAvoidDefaultExpertName());
                    String expertPhone = this.expertService.getById(avoid.getAvoidDefaultExpert()).getExpertPhone();
                    expertExtractVo.setExpertPhone(expertPhone);
                    expertAvoidVos.add(expertExtractVo);
                }
                if (avoid.getAvoidUnit()!=null){
                    avoidUnit.add(avoid.getAvoidUnit());
                }
                if (avoid.getAvoidRegion()!=null){
                    avoidRegion.add(avoid.getAvoidRegion());
                }
            });
        }
        ExtractAvoidOtherVo avoidOtherVo=ExtractAvoidOtherVo.builder()
                .avoidRegion(avoidRegion.toString())
                .avoidUnit(avoidUnit.toString())
                .build();
        extractInfoVo.setExpertExtractCondition(expertExtractVos);
        extractInfoVo.setOtherConditions(otherConditions);
        extractInfoVo.setExpertAvoid(expertAvoidVos);
        extractInfoVo.setExtractAvoidOther(avoidOtherVo);
        return extractInfoVo;
    }

    /**
     * 抽取专家
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void extractExpert(Long id) {
        List<ExtractAvoid> extractAvoidList = this.extractAvoidService.lambdaQuery().eq(ExtractAvoid::getProjectId, id).list();
        List<ExtractCondition> conditionList = this.conditionService.lambdaQuery().eq(ExtractCondition::getProjectId, id).list();
        Set<Long> extracted=new HashSet<>();
        ArrayList<Long> avoidExpert=new ArrayList<>();
        ArrayList<String> avoidUnit=new ArrayList<>();
        ArrayList<String> avoidRegion=new ArrayList<>();
        //处理数据
        extractAvoidList.forEach(avoid->{
            if (avoid.getAvoidDefaultExpert()!=null){
                avoidExpert.add(avoid.getAvoidDefaultExpert());
            }
            if (avoid.getAvoidUnit()!=null){
                avoidUnit.add(avoid.getAvoidUnit());
            }
            if (avoid.getAvoidRegion()!=null){
                avoidRegion.add(avoid.getAvoidRegion());
            }
        });
        conditionList.forEach(condition -> {
            if (condition.getExtractDefaultExpert()!=null){
                extracted.add(condition.getExtractDefaultExpert());
            }else {
                List<Long> expertList = this.expertService.lambdaQuery()
                        .notIn(avoidExpert.size() > 0, Expert::getId, avoidExpert)
                        .eq(Expert::getDeleted,0)
                        .and(avoidUnit.size()>0||avoidRegion.size()>0,wrapper -> {
                            avoidUnit.forEach(unit -> {
                                wrapper.notLike(Expert::getExpertUnit,unit);
                            });
                            avoidRegion.forEach(region->{
                                wrapper.notLike(Expert::getExpertRegion,region);
                            });
                        })
                        .eq(condition.getExtractCategory()!=null,Expert::getExpertCategory,condition.getExtractCategory())
                        .eq(StringUtils.isNotEmpty(condition.getExpertTitle()),Expert::getExpertTitle,condition.getExpertTitle())
                        .notIn(extracted.size()>0,Expert::getId,extracted)
                        .list().stream().map(Expert::getId).toList();

                //删除今年抽取超过10次的情况
                List<Long> notOverList=new ArrayList<>(this.extractResultService.queryExtractedOver(expertList));
                if (notOverList.size()<condition.getExtractNumber()){
                    throw  new AddException("符合条件专家人数不满足抽取条件");
                }
                Collections.shuffle(notOverList);
                for (int i = 0; i < condition.getExtractNumber(); i++) {
                    extracted.add(notOverList.get(i));
                }
            }
        });
        String attendanceCode = RandomStringUtils.randomAlphanumeric(6);
        List<ExtractResult> extractResults = extracted.stream().map(expert -> {
            ExtractResult result = ExtractResult.builder()
                    .expertId(expert)
                    .projectId(id)
                    .attendanceCode(attendanceCode)
                    .createUser(BaseContext.getCurrentId())
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .updateUser(BaseContext.getCurrentId())
                    .build();
            service.send(expert,id);
            return result;
        }).toList();
        Project project = this.projectService.getProjectById(id);
        project.setProjectStatus(ProjectStatus.DRAWN.getCode());
        project.setUpdateUser(BaseContext.getCurrentId());
        project.setUpdateTime(LocalDateTime.now());
        this.projectService.updateById(project);
        this.extractResultService.saveBatch(extractResults);
    }
}
